package com.ruoyi.binance.service;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.binance.api.KlinesApi;
import com.ruoyi.binance.domain.Binance15macd;
import com.ruoyi.binance.domain.Binance15minAverage;
import com.ruoyi.binance.domain.Binance15minDayAve;
import com.ruoyi.binance.mapper.Binance15macdMapper;
import com.ruoyi.binance.mapper.Binance15minAverageMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Component
public class AsyncKData {

    @Autowired
    private IBinanceMinKService binanceMinKService;
    @Autowired
    private IBinanceDailyMarketService binanceDailyMarketService;
    @Autowired
    private IBinance15minKService binance15minKService;
    @Autowired
    private Binance15macdMapper binance15macdMapper;
    @Autowired
    private Binance15minAverageMapper binance15minAverageMapper;

    @Async
    public void saveKData(String code) {
        long l = System.currentTimeMillis();
        JSONArray minK = KlinesApi.minK(code, l - 1000 * 60 * 60 * 24, l - 1000 * 60 * 60 * 12);
        JSONArray minKTwo = KlinesApi.minK(code, l - 1000 * 60 * 60 * 12, l);
        minK.addAll(minKTwo);
        binanceMinKService.saveOrUpdateMinK(code, minK);
        saveOrUpdate15MinAveragePrice(code, minK);

        JSONArray dailyMarket = KlinesApi.minK(code, l - 1000 * 60 * 60 * 24 * 4, l, "1d");
        binanceDailyMarketService.saveOrUpdateTradingDay(code, dailyMarket);

        JSONArray jsonArray = KlinesApi.min15K(code, l - 1000 * 60 * 60 * 24, l);
        binance15minKService.saveOrUpdateMinK(code, jsonArray);
        saveOrUpdate15Macd(code, jsonArray);
    }

    private void saveOrUpdate15MinAveragePrice(String code, JSONArray jsonArray) {
        if (jsonArray == null || jsonArray.isEmpty()){
            return;
        }
        for(int i = 15; i < jsonArray.size(); i++){
            Date time = jsonArray.getJSONArray(i).getDate(0);
            BigDecimal close = jsonArray.getJSONArray(i).getBigDecimal(4);
            //计算15分钟均价
            BigDecimal amount = new BigDecimal("0");
            BigDecimal volume = new BigDecimal("0");
            for(int k = i-15; k < i; k++){
                amount = amount.add(jsonArray.getJSONArray(k).getBigDecimal(7));
                volume = volume.add(jsonArray.getJSONArray(k).getBigDecimal(5));
            }
            //amount ||  volume == 0
            BigDecimal averagePrice15 = close;
            if(volume.compareTo(BigDecimal.ZERO) != 0 && amount.compareTo(BigDecimal.ZERO) != 0){
                averagePrice15 = amount.divide(volume, 8, RoundingMode.HALF_UP);
            }
            Binance15minAverage stock15minAverage = new Binance15minAverage();
            stock15minAverage.setCode(code);
            stock15minAverage.setTime(time);
            stock15minAverage.setPrice(averagePrice15);
            int i15 = binance15minAverageMapper.updateBinance15minAverage(stock15minAverage);
            if (i15 == 0) {
                binance15minAverageMapper.insertBinance15minAverage(stock15minAverage);
            }
        }
    }

    private void saveOrUpdate15Macd(String code, JSONArray jsonArray) {
        if (jsonArray == null || jsonArray.isEmpty()){
            return;
        }
        List<BigDecimal> difList = new ArrayList<>();
        Binance15macd last15macd = null;
        for(int i = 26; i < jsonArray.size(); i++){
            Date time = jsonArray.getJSONArray(i).getDate(0);
            Date closeTime = jsonArray.getJSONArray(i).getDate(6);
            BigDecimal close = jsonArray.getJSONArray(i).getBigDecimal(4);
            //计算12周期EMA（快线）   计算26周期EMA（慢线）  计算差离值（DIF）
            BigDecimal ema12 = null;
            BigDecimal lastEma12 = null;
            BigDecimal ema26 = null;
            BigDecimal lastEma26 = null;
            BigDecimal dif = null;
            BigDecimal lastDea = null;
            BigDecimal dea = null;
            BigDecimal bar = null;
            //当前EMA(12) = (当前15分钟收盘价 × 2/13) + (前一根K线EMA(12) × 11/13)
            if(last15macd == null || last15macd.getEma12() == null){
                BigDecimal closeTmp = new BigDecimal("0");
                for(int k = 13; k < 26; k++){
                    closeTmp = closeTmp.add(jsonArray.getJSONArray(k).getBigDecimal(4));
                }
                lastEma12 = closeTmp.divide(new BigDecimal(13), 10, RoundingMode.HALF_UP);
            }else {
                lastEma12 = last15macd.getEma12();
            }
            ema12 = close.multiply(new BigDecimal("2")).divide(new BigDecimal("13"), 10, RoundingMode.HALF_UP)
                    .add(lastEma12.multiply(new BigDecimal("11")).divide(new BigDecimal("13"), 10, RoundingMode.HALF_UP));
            //当前EMA(26) = (当前15分钟收盘价 × 2/27) + (前一根K线EMA(26) × 25/27)
            if(last15macd == null || last15macd.getEma26() == null){
                BigDecimal closeTmp = new BigDecimal("0");
                for(int k = 0; k < 26; k++){
                    closeTmp = closeTmp.add(jsonArray.getJSONArray(k).getBigDecimal(4));
                }
                lastEma26 = closeTmp.divide(new BigDecimal(26), 10, RoundingMode.HALF_UP);
            }else {
                lastEma26 = last15macd.getEma26();
            }
            ema26 = close.multiply(new BigDecimal("2")).divide(new BigDecimal("27"), 10, RoundingMode.HALF_UP)
                    .add(lastEma26.multiply(new BigDecimal("25")).divide(new BigDecimal("27"), 10, RoundingMode.HALF_UP));
            //DIF = EMA(12) - EMA(26)
            if(ema12 != null && ema26 != null){
                dif = ema12.subtract(ema26);
                if(difList.size() < 9){
                    difList.add(dif);
                }
            }
            //计算DIF的9周期DEA
            if (last15macd == null || last15macd.getDea() == null){
                if(difList.size() == 9){
                    lastDea = difList.stream().reduce(BigDecimal::add).get().divide(new BigDecimal(9), 10, RoundingMode.HALF_UP);
                }
            }else {
                lastDea = last15macd.getDea();
            }
            //当前DEA = (当前DIF × 0.2) + (前一个DEA × 0.8)
            if(lastDea != null){
                dea = dif.multiply(new BigDecimal("0.2")).add(lastDea.multiply(new BigDecimal("0.8")));
            }
            //BAR = (DIF - DEA)
            if(dea != null){
                bar = dif.subtract(dea);
            }
            Binance15macd binance15macd = new Binance15macd();
            binance15macd.setCode(code);
            binance15macd.setTime(time);
            binance15macd.setEma12(ema12);
            binance15macd.setEma26(ema26);
            binance15macd.setDif(dif);
            binance15macd.setDea(dea);
            binance15macd.setBar(bar);
            binance15macd.setCloseTime(closeTime);
            binance15macd.setUpdateTime(new Date());
            int update = binance15macdMapper.updateBinance15macd(binance15macd);
            if (update == 0) {
                binance15macd.setCreateTime(new Date());
                binance15macdMapper.insertBinance15macd(binance15macd);
            }
            last15macd = binance15macd;
        }
    }
}
